package com.train.mgr.modules.biz.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.unit.DataUnit;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.train.common.enums.ProjectTypeEnum;
import com.train.common.model.PageResult;
import com.train.mgr.modules.biz.dto.StatLessonGroupTraineeDTO;
import com.train.mgr.modules.biz.dto.StatLessonTraineeDTO;
import com.train.mgr.modules.biz.dto.request.StatQueryDTO;
import com.train.mgr.modules.biz.entity.Course;
import com.train.mgr.modules.biz.entity.StatLessonGroup;
import com.train.mgr.modules.biz.entity.StatLessonTrainee;
import com.train.mgr.modules.biz.mapper.StatLessonTraineeMapper;
import com.train.mgr.modules.biz.service.ICourseService;
import com.train.mgr.modules.biz.service.IStatLessonTraineeService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 课时学员学习统计表 服务实现类
 * </p>
 *
 * @author cxg
 * @date 2025-10-11
 */
@Slf4j
@RequiredArgsConstructor
@Service("IStatLessonTraineeService")
public class StatLessonTraineeServiceImpl extends ServiceImpl<StatLessonTraineeMapper, StatLessonTrainee> implements IStatLessonTraineeService {

    private final ICourseService courseService;
    /**
     * 统计课时学习情况-按学员
     * @param params
     * @return
     */
    @Override
    public PageResult<StatLessonTrainee> lessonTraineeList(StatQueryDTO params){
        Page<StatLessonTrainee> page = params.buildPage();
        LambdaQueryWrapper<StatLessonTrainee> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.and(
                StrUtil.isNotBlank(params.getQ()),
                wrapper -> wrapper.like(StatLessonTrainee::getNickName, params.getQ())
                        .or()
                        .like(StatLessonTrainee::getUsername, params.getQ())
        );
        queryWrapper.eq(StatLessonTrainee::getCourseId,params.getCourseId());
        queryWrapper.eq(params.getLessonId()!=null,StatLessonTrainee::getLessonId,params.getLessonId());
        queryWrapper.orderByAsc(StatLessonTrainee::getJoinTime);
        Page<StatLessonTrainee> resultPage = baseMapper.selectPage(page, queryWrapper);
        if (resultPage != null && CollUtil.isNotEmpty(resultPage.getRecords())){
            List<StatLessonTrainee> records = resultPage.getRecords();
            for (StatLessonTrainee statLessonTrainee : records) {
                String lessonFinishState = statLessonTrainee.getLessonFinishState();
                if (StrUtil.isNotBlank(lessonFinishState)) {
                    statLessonTrainee.setLessonFinishState("1".equals(lessonFinishState) ? "已完成" : "未完成");
                }
            }
        }
        return PageResult.of(resultPage, StatLessonTrainee.class);

    }

    @Override
    @Transactional
    public void buildLessonTraineeStat(String courseId) {
        List<StatLessonTrainee> stats = new ArrayList<>();
        UpdateWrapper<StatLessonTrainee> updateWrapper = new UpdateWrapper<>();
        updateWrapper.ne(StrUtil.isBlank(courseId),"id", 0L);
        updateWrapper.eq(StrUtil.isNotBlank(courseId),"course_id", courseId);
        baseMapper.delete(updateWrapper);
        List<Course> courseList;
        if (StrUtil.isBlank(courseId)){
            courseList = courseService.getCourseList();
        } else {
            Course course = courseService.getById(courseId);
            courseList = Collections.singletonList(course);
        }
        for (Course course : courseList) {
            List<StatLessonTraineeDTO> statLessonTraineeDTOS = baseMapper.buildLessonTraineeStat(course.getId(), null, null);
            if (CollUtil.isEmpty(statLessonTraineeDTOS)) {
                continue;
            }
            
            Map<Long, List<StatLessonTraineeDTO>> lessons = statLessonTraineeDTOS.stream()
                    .collect(Collectors.groupingBy(StatLessonTraineeDTO::getLessonId));
                    
            for (Map.Entry<Long, List<StatLessonTraineeDTO>> lessonEntry : lessons.entrySet()) {
                Long lessonId = lessonEntry.getKey();
                List<StatLessonTraineeDTO> dtos = lessonEntry.getValue();
                
                Map<Long, List<StatLessonTraineeDTO>> userGrouped = dtos.stream()
                        .collect(Collectors.groupingBy(StatLessonTraineeDTO::getUserId));
                        
                for (Map.Entry<Long, List<StatLessonTraineeDTO>> userEntry : userGrouped.entrySet()) {
                    List<StatLessonTraineeDTO> userDtos = userEntry.getValue();
                    List<StatLessonTraineeDTO> readingProjects = userDtos.stream()
                            .filter(x -> ProjectTypeEnum.READING.getCode().equals(x.getExerciseType()))
                            .collect(Collectors.toList());

                    StatLessonTraineeDTO statLessonTraineeDTO = userDtos.get(0);
                    StatLessonTrainee stat = new StatLessonTrainee();
                    int readingCount = readingProjects.size();
                    
                    stat.setCourseId(course.getId());
                    stat.setLessonId(lessonId);
                    stat.setUsername(statLessonTraineeDTO.getUsername());
                    stat.setNickName(statLessonTraineeDTO.getNickName());
                    stat.setCustomerId(course.getCustomerId());
                    Integer isFinish = statLessonTraineeDTO.getIsFinish();
                    if (isFinish == null){
                        stat.setLessonFinishState("0");
                    } else {
                        stat.setLessonFinishState(isFinish.toString());
                    }
                    stat.setLessonExercisesNum((int) userDtos.stream().filter(x -> x.getComprehensiveScore() != null).count());
                    stat.setGroupId(statLessonTraineeDTO.getGroupId());
                    stat.setReadRepeatedTimes(readingCount);

                    // 设置阅读最高分
                    stat.setReadMaxScore(readingProjects.stream()
                            .map(StatLessonTraineeDTO::getComprehensiveScore)
                            .max(BigDecimal::compareTo)
                            .orElse(BigDecimal.ZERO));
                    if (readingCount == 0){
                        stat.setLessonOverallScore(BigDecimal.ZERO);
                        stat.setReadAvgScore(BigDecimal.ZERO);
                        stat.setReadPassRate("0");
                    } else {
                        // 计算综合平均分
                        BigDecimal maxReadScore = stat.getReadMaxScore();
                        // 筛选出脱稿演练练习项目
                        List<StatLessonTraineeDTO> practiceProjects = userDtos.stream()
                                .filter(x -> ProjectTypeEnum.PRACTICE.getCode().equals(x.getExerciseType()))
                                .collect(Collectors.toList());
                        BigDecimal maxPracticeScore = practiceProjects.stream()
                                .map(StatLessonTraineeDTO::getComprehensiveScore).filter(Objects::nonNull)
                                .max(BigDecimal::compareTo)
                                .orElse(BigDecimal.ZERO);
                        // 筛选出模拟对话练习项目
                        List<StatLessonTraineeDTO> simulatedProjects = userDtos.stream()
                                .filter(x -> ProjectTypeEnum.SIMULATED.getCode().equals(x.getExerciseType()))
                                .collect(Collectors.toList());
                        BigDecimal maxSimulatedScore = simulatedProjects.stream()
                                .map(StatLessonTraineeDTO::getComprehensiveScore).filter(Objects::nonNull)
                                .max(BigDecimal::compareTo)
                                .orElse(BigDecimal.ZERO);
                        int projectNum = 1 + (practiceProjects.size() > 0 ? 1 : 0) + (simulatedProjects.size() > 0 ? 1 : 0);
                        BigDecimal lessonScore = maxReadScore.add(maxPracticeScore).add(maxSimulatedScore).divide(BigDecimal.valueOf(projectNum), 1, RoundingMode.HALF_UP);
                        stat.setLessonOverallScore(lessonScore);

                        // 计算阅读平均分
                        BigDecimal totalScoreReading = readingProjects.stream()
                                .map(StatLessonTraineeDTO::getComprehensiveScore)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                        stat.setReadAvgScore(totalScoreReading.divide(new BigDecimal(readingCount), 1, RoundingMode.HALF_UP));

                        // 设置加入时间
                        String joinTime = statLessonTraineeDTO.getJoinTime();
                        if (StrUtil.isNotBlank(joinTime)) {
                            DateTime parsedTime = DateUtil.parse(joinTime, "yyyy-MM-dd HH:mm:ss");
                            stat.setJoinTime(parsedTime);
                        }

                        // 计算通过率
                        long passCount = readingProjects.stream()
                                .map(StatLessonTraineeDTO::getPassingState)
                                .filter(state -> Integer.valueOf(1).equals(state))
                                .count();
                        BigDecimal passRate = new BigDecimal(passCount)
                                .divide(new BigDecimal(readingCount), 3, RoundingMode.HALF_UP)
                                .multiply(BigDecimal.valueOf(100))
                                .setScale(3, RoundingMode.HALF_UP);
                        if (passRate.compareTo(BigDecimal.ZERO) == 0){
                            stat.setReadPassRate("0");
                        } else if (passRate.compareTo(BigDecimal.valueOf(100)) == 0){
                            stat.setReadPassRate("100");
                        } else {
                            stat.setReadPassRate(passRate.toPlainString());
                        }
                    }
                    // 计算学习时长（分钟）
                    int totalTime = userDtos.stream()
                            .map(StatLessonTraineeDTO::getUseTime).filter(Objects::nonNull)
                            .reduce(0, Integer::sum);
                    BigDecimal durationInMinutes = new BigDecimal(totalTime)
                            .divide(new BigDecimal(60), 0, RoundingMode.HALF_UP);
                    stat.setLessonLearnDuration(durationInMinutes);
                    
                    stats.add(stat);
                }
            }
        }
        
        if (CollUtil.isNotEmpty(stats)) {
            saveBatch(stats);
        }
    }


}
